#include <iostream>
#include <string>
#include <vector>
#include <filesystem>
#include <sys/stat.h>
#include "../source/server.hpp"

static size_t Split(const std::string &src, const std::string &sep, std::vector<std::string> *arry)
{
    int offset = 0;
    while (offset < src.size())
    {
        int pos = src.find(sep, offset); // 在src offset 偏移量处开始向后查找 sep 字串，返回找到的起始位置
        if (pos == std::string::npos)
        {
            arry->push_back(src.substr(offset));
            return arry->size();
        }
        if (pos == offset)
        {
            offset += sep.size();
            continue;
        }
        arry->push_back(src.substr(offset, pos - offset));
        offset = pos + sep.size();
    }
    return arry->size();
}

// 读取文件的所有内容
static bool ReadFile(const std::string &filename, std::string *buf)
{
    std::ifstream ifs(filename, std::ios::binary);
    if (!ifs.is_open())
    {
        LOG(LogLevel::ERROR) << filename << " OPEN FAILED!";
        return false;
    }
    size_t fsize = 0;
    ifs.seekg(0, ifs.end);
    fsize = ifs.tellg();
    ifs.seekg(0, ifs.beg);
    buf->resize(fsize);
    ifs.read(&(*buf)[0], fsize);
    if (!ifs.good())
    {
        LOG(LogLevel::ERROR) << "READ " << filename << " FILE FAILED!";
        ifs.close();
        return false;
    }
    ifs.close();
    return true;
}

static bool WriteFile(const std::string filename, const std::string &buf)
{
    std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);
    if (!ofs.is_open())
    {
        LOG(LogLevel::ERROR) << filename << " OPEN FAILED!";
        return false;
    }
    ofs.write(buf.c_str(), buf.size());
    if (!ofs.good())
    {
        LOG(LogLevel::ERROR) << "WRITE " << filename << " FILE FAILED!";
        ofs.close();
        return false;
    }
    ofs.close();
    return true;
}

static std::string UrlEncode(const std::string &url, bool convert_space_to_plus)
{
    std::string res;
    for (auto &c : url)
    {
        if (c == '.' || c == '~' || c == '_' || c == '-' || isalpha(c))
        {
            res += c;
            continue;
        }
        if (c == ' ' && convert_space_to_plus)
        {
            res += '+';
            continue;
        }
        // 剩下的字符都是需要编码成 %HH 格式
        char tmp[4] = {0};
        snprintf(tmp, sizeof(tmp), "%%%02X", c);
        res += tmp;
    }
    return res;
}

static char HEXTOI(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    if (c >= 'A' && c <= 'Z')
        return c - 'A' + 10;
    if (c >= 'a' && c <= 'z')
        return c - 'a' + 10;
    return -1;
}

// URL 解码
static std::string UrlDecode(const std::string &url, bool convert_space_to_plus)
{
    // 遇到了%，则将紧随其后的2个字符，转换为数字，第⼀个数字左移4位，然后加上第二个数字 + -> 2b %2b->2 << 4 + 11
    std::string res;
    for (int i = 0; i < url.size(); i++)
    {
        if (url[i] == '+' && convert_space_to_plus)
        {
            res += ' ';
            continue;
        }

        if (url[i] == '%' && i + 2 < url.size())
        {
            char v1 = HEXTOI(url[i + 1]);
            char v2 = HEXTOI(url[i + 2]);
            char v = (v1 << 4) + v2;
            res += v;
            i += 2;
        }
        else
            res += url[i];
    }
    return res;
}

static std::string StatusDesc(int status)
{
    std::unordered_map<int, std::string> status_msg = {
        {100, "Continue"},
        {101, "Switching Protocol"},
        {102, "Processing"},
        {103, "Early Hints"},
        {200, "OK"},
        {201, "Created"},
        {202, "Accepted"},
        {203, "Non-Authoritative Information"},
        {204, "No Content"},
        {205, "Reset Content"},
        {206, "Partial Content"},
        {207, "Multi-Status"},
        {208, "Already Reported"},
        {226, "IM Used"},
        {300, "Multiple Choice"},
        {301, "Moved Permanently"},
        {302, "Found"},
        {303, "See Other"},
        {304, "Not Modified"},
        {305, "Use Proxy"},
        {306, "unused"},
        {307, "Temporary Redirect"},
        {308, "Permanent Redirect"},
        {400, "Bad Request"},
        {401, "Unauthorized"},
        {402, "Payment Required"},
        {403, "Forbidden"},
        {404, "Not Found"},
        {405, "Method Not Allowed"},
        {406, "Not Acceptable"},
        {407, "Proxy Authentication Required"},
        {408, "Request Timeout"},
        {409, "Conflict"},
        {410, "Gone"},
        {411, "Length Required"},
        {412, "Precondition Failed"},
        {413, "Payload Too Large"},
        {414, "URI Too Long"},
        {415, "Unsupported Media Type"},
        {416, "Range Not Satisfiable"},
        {417, "Expectation Failed"},
        {418, "I'm a teapot"},
        {421, "Misdirected Request"},
        {422, "Unprocessable Entity"},
        {423, "Locked"},
        {424, "Failed Dependency"},
        {425, "Too Early"},
        {426, "Upgrade Required"},
        {428, "Precondition Required"},
        {429, "Too Many Requests"},
        {431, "Request Header Fields Too Large"},
        {451, "Unavailable For Legal Reasons"},
        {501, "Not Implemented"},
        {502, "Bad Gateway"},
        {503, "Service Unavailable"},
        {504, "Gateway Timeout"},
        {505, "HTTP Version Not Supported"},
        {506, "Variant Also Negotiates"},
        {507, "Insufficient Storage"},
        {508, "Loop Detected"},
        {510, "Not Extended"},
        {511, "Network Authentication Required"}};
    auto it = status_msg.find(status);
    if (it != status_msg.end())
    {
        return it->second;
    }
    return "Unknow";
}

// 判断一个文件是否是一个目录
static bool IsDirectory(const std::string &filename)
{
    struct stat st;
    int ret = stat(filename.c_str(), &st);
    if (ret < 0)
        return false;
    return S_ISDIR(st.st_mode);
}
// 判断一个文件是否是一个普通文件
static bool IsRegular(const std::string &filename)
{
    struct stat st;
    int ret = stat(filename.c_str(), &st);
    if (ret < 0)
        return false;
    return S_ISREG(st.st_mode);
}

static bool ValidPath(const std::string &path)
{
    // 思想：按照 / 进⾏路径分割,根据有多少⼦目录,计算目录深度,有多少层，深度不能⼩于 0
    int level = 0;
    std::vector<std::string> subdir;
    Split(path, "/", &subdir);
    for (auto &dir : subdir)
    {
        if (dir == "..")
        {
            level--; // 任意⼀层⾛出相对根目录，就认为有问题
            if (level < 0)
                return false;
        }
        else
            level++;
    }
    return true;
}

int main()
{
    // std::string str = "abc,,,def,ghk,";
    // std::vector<std::string> arry;
    // Split(str, ",", &arry);
    // for (auto &s : arry)
    // {
    //     std::cout << s << std::endl;
    // }

    // std::string buf;
    // ReadFile("./eventfd.c", &buf);

    // WriteFile("./tttttt.txt", buf);

    // std::string str = "/login?user=bite&passwd=C++  ";
    // std::string res1 = UrlEncode(str, true);
    // std::string res2 = UrlDecode(res1, true);

    // std::cout << res1 << '\n'
    //           << res2 << '\n';

    // std::cout << StatusDesc(203) << '\n';

    // std::cout << IsDirectory("./testdir") << '\n'
    //           << IsRegular("./testdir") << '\n';


    std::cout << ValidPath("/../../../index.html") << '\n';

    return 0;
}